<html>
    <head>
        <title>link game</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <style>
            body { background-color: #f3f3f3; }
            .cell {
                width: 32px; height: 32px;line-height: 32px;
                cursor: pointer;
                min-width: 32px; min-height: 32px;
                text-align: center;
                /*background-color: #d3d3d3;*/
                border: 1px solid #d3d3d3;
                color: gray;
                border-radius: 2px;
                /*font-size: 8px;*/
            }
            /*.cell:active { background-color:#f3f3f3; }*/
            .cell:hover { opacity: 0.9 }
            table { margin: auto; }
            img { width: 100%;height: 100%; }
        </style>
    </head>
    <body>
        <div style="text-align: center;font-size: 24px;margin: 8px;font-family: 楷体;color: rgb(50, 150, 255, 0.4)">
            <h2>Fruit Link Game</h2>
        </div>
        <div>
            <table id="tb" onselectstart="return false;"></table>
        </div>
        <div style="text-align: center;">
            <label><input name="way" type="radio" checked onclick="changeWay('dfs')" />深搜</label>
            <label><input name="way" type="radio" onclick="changeWay('bfs')" />广搜</label>
        </div>
        <!--<div style="text-align: center;">
            <label><input name="autoLink" type="radio" value="false" checked onclick="startAutoLink(false)" />手动</label>
            <label><input name="autoLink" type="radio" value="true" onclick="startAutoLink(true)" />自动</label>
        </div>-->
        <div style="text-align: center;">
            <label><input name="mode" type="radio" onclick="changeMode('')" />普通模式</label>
            <label><input name="mode" type="radio" checked onclick="changeMode('演示模式')" />演示模式</label>
            <div>（演示模式下将显示搜索路径）</div>
        </div>
        <div style="text-align: center">
            演示速度<span id="speed_val">5</span>
            <input id="speed_fac" type="range" oninput="changeRange()" onchange="changeRange()" max="10" step="1" min="1" value="5">
        </div>
    </body>

    <!--广度优先搜索实现算法 (路径最短)-->
    <!--<script id="jscript" src="js/core-bfs.js"></script>-->

    <!--深度优先搜索实现算法 (路径不一定最短)-->
    <script id="jscript" src="js/core-dfs.js"></script>

    <script>
        const WIDTH = 16; // 宽
        const HEIGHT = 10; // 高
        // 水果品种数 1 ~ 20
        const FRUIT_COUNT = 10;

        // 消失动画样式
        const DISAPPEAR_FACE = '*';

        // 演示速度因数
        let speed_fac = 5.0;
        // “演示模式”下将显示搜索路径
        let MODE = '';

        // 辅助变量
        let animating = false;
        let animateList = undefined;
        let tmpNode;

        // 准备0 ~ 20个水果图片
        let imgList = [];
        for (let i = 1; i <= FRUIT_COUNT;i++) {
            imgList.push('<img src="img/sg'+(i<10?'0'+i:i)+'.png">');
        }

        // 二维核心数组 （长宽乘积需为列表长度的整数倍）
        let a = createAry(WIDTH, HEIGHT, imgList);
        // a = createAry(WIDTH, HEIGHT, 'ABCDEFG123456789'.split(''));

        // UI数组
        let aa = initWith(a);

        // 搜索方式 bfs广搜 dfs深搜
        changeWay('dfs');  // bfs or dfs
        setTimeout(() => {
            changeMode('演示模式')
        }, 1000);
        // 创建二维数组存Dom元素
        function initWith(a) {
            let aa = [];
            let tb = document.querySelector('#tb');
            for (let i=0;i<a.length;i++) {
                let tr = document.createElement('tr');
                aa.push([]);
                for (let j=0;j<a[i].length;j++) {
                    let td = document.createElement('td');
                    tr.appendChild(td);
                    td.onclick = () => clicked(a, aa, i, j);
                    td.className = 'cell';
                    aa[i].push(td);
                    fitWith(aa[i][j], a[i][j] == 0?'':a[i][j]);
                }
                tb.appendChild(tr);
            }
            return aa;
        }

        // 塞数据给元素
        function fitWith(e, data) {
            if (data == null) return;
            e.innerHTML = data;
        }

        // 辅助变量
        let lastClicked = { x: 0, y: 0, d: null };
        // 点击事件
        function clicked(a, aa, i, j) {
            aa[lastClicked.x][lastClicked.y].style = 'border: 1px solid #d3d3d3';
            aa[i][j].style = 'border: 1px solid gray';
            if (lastClicked.d === a[i][j] && !animating) {
                let node = disappear(a, i, j, lastClicked.x, lastClicked.y);
                if (node) {
                    tmpNode = node;
                    clean(tmpNode);
                } else {
                    animateList = [];
                }
            }
            lastClicked = { x:i, y: j, d: a[i][j] };
        }

        function changeWay(way) {
            let node = document.querySelector('#jscript');
            node.parentNode.removeChild(node);
            node = document.createElement('script');
            node.setAttribute('id', 'jscript');
            node.setAttribute('src', 'js/core-' + way + '.js');
            document.body.appendChild(node);
        }

        function changeRange() {
            speed_fac = parseFloat(document.querySelector('#speed_fac').value);
            document.querySelector('#speed_val').innerText = speed_fac;
        }

        /**
         * 演示模式下显示搜索路径
         */
        function changeMode(mode) {
            MODE = mode;
            return animateList = mode === '演示模式' ? [] : undefined;
        }

        function getArrow(item, ans) {
            let preNode = item.pre;
            if (!preNode) return ans;
            // const d = [{x:-1,y:0},{x:0,y:-1},{x:1,y:0},{x:0,y:1}];
            const m = ['←', '↓', '→', '↑'];
            let c = DISAPPEAR_FACE;
            if (preNode.x < item.x) {
                c = m[1];
            } else if (preNode.x > item.x) {
                c = m[3];
            } else if (preNode.y > item.y) {
                c = m[0];
            } else if (preNode.y < item.y) {
                c = m[2];
            }
            return c;
        }

        function animateSearch(animateList, p, callback) {
            if (MODE === '演示模式' && p < animateList.length) {
                animating = true;
                let item = animateList[p];
                if (item.type[0] === '+') {
                    fitWith(aa[item.x][item.y], `${getArrow(item, p)}`);
                } else if (item.type[0] === '-') {
                    fitWith(aa[item.x][item.y], '');
                }
                setTimeout(() => { animateSearch(animateList, p + 1, callback); }, 100 / speed_fac);
            } else {
                animating = false;
                callback();
            }
        }


        // 消除
        function clean(node) {
            if (!node) return;
            animateSearch(animateList, 0, () => {
                // 播放消失动画
                disappearing(node, aa, () => {
                    let p = node;
                    while (p) {
                        fitWith(aa[p.x][p.y], "");
                        p = p.pre;
                    }
                    // 清除残余
                    for (let tmp in animateList) {
                        fitWith(aa[animateList[tmp].x][animateList[tmp].y], "");
                    }
                    animateList = changeMode(MODE);
                    tmpNode = null;
                });
            });
        }

        // 消失动画
        function disappearing(node, aa, callback) {
            if (!node) {
                if (callback) callback();
                return;
            }
            fitWith(aa[node.x][node.y], DISAPPEAR_FACE);
            setTimeout(()=>disappearing(node.pre, aa, callback), 200 / speed_fac);
        }

        // 消除一半
        (()=> {for (let i = 0; i < WIDTH * HEIGHT / 4; found = false, autoLink(), i++);})();

        function autoLink() {
            let data = {};
            for (let i = 0; i <= HEIGHT; i++) {
                for (let j = 0; j <= WIDTH; j++) {
                    if (!data[a[i][j]])
                        data[a[i][j]] = [];
                    data[a[i][j]].push({x: i, y: j});
                }
            }
            for (const dataKey in data) {
                if (dataKey === '0') continue;
                let list = data[dataKey];
                for (let i = 0; i < list.length; i++) {
                    let x0 = list[i].x;
                    let y0 = list[i].y;
                    for (let j = i + 1; j < list.length; j++) {
                        let targetx = list[j].x;
                        let targety = list[j].y;
                        let result = false;

                        if (typeof dfs !== 'undefined') {
                            dfs(a, {x:x0, y:y0, pre:null, zCount:0}, {}, targetx, targety, (res) => result = res);
                        } else if (typeof bfs !== 'undefined') {
                            bfs(a, x0, y0, targetx, targety, (res) => result = res);
                        }
                        if (result) {
                            clicked(a, aa, x0, y0);
                            clicked(a, aa, targetx, targety);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    </script>
</html>
